home *** CD-ROM | disk | FTP | other *** search
/ Saar AMOK 2 / Saar AMOK II - Oktober 1994 (1994)(Kreativ Marketing)(DE)[!][I-7598].iso / disks / 651_700 / 662 / scsiutil / scsiutil.c < prev    next >
C/C++ Source or Header  |  1994-01-04  |  72KB  |  2,725 lines

  1. /*
  2.  *****    SCSIutil
  3.  *
  4.  *    A utility to do some low-level operations to a SCSI disk, e.g.
  5.  *
  6.  *        - start/stop motor
  7.  *        - read sectors
  8.  *        - read disk capacity info
  9.  *        - get inquiry info (manufacturers name etc)
  10.  *        - seek to a sector's cylinder (use to park heads)
  11.  *        - play audio tracks of a CD-DA
  12.  *        - eject/insert a medium
  13.  *        - read digital data off audio CDs (with Sony 8003 = Apple CD300
  14.  *          and Toshiba 3401)
  15.  *        - set output volume of a CD-ROM drive
  16.  *
  17.  *    NOTE:  this program is based on SCSI information taken from
  18.  *           the accompanying documentation of a NEC D3841 SCSI disk.
  19.  *           I don't know the extent to which SCSI standards are
  20.  *           supported by that disk.
  21.  *
  22.  *           These commands work on the above disk. But a seek to
  23.  *           sector -1 (park on the NEC disk) fails on my Quantum 105.D
  24.  *
  25.  *    Program returns:
  26.  *    1 - init didn't work (maybe allocmem failed, etc.)
  27.  *    2 - wrong parameter count
  28.  *    3 - wrong parameter
  29.  *
  30.  *****    Written by Gary Duncan
  31.  *
  32.  *    Bug reports etc via e-mail to gduncan@philips.oz.au) , or mail to
  33.  *
  34.  *    Gary Duncan
  35.  *    Philips PTS
  36.  *      23 Lakeside Dr
  37.  *    Tally-Ho Technology Park
  38.  *    Burwood East Vic 3151
  39.  *    Australia
  40.  *
  41.  * New features and rewrites by:
  42.  *
  43.  *    The Software Brewery
  44.  *    Heiko Rath
  45.  *    Raiffeisenstr.10a
  46.  *    D-64331 Weiterstadt
  47.  *    Germany
  48.  *
  49.  *    EMail: hr@brewhr.swb.de
  50.  *
  51.  *****    Freely distributable for non-commercial purposes
  52.  *
  53.  *    Compiles under Lattice 6.50
  54.  *    - needs AmigaDos 2.0  #includes
  55.  *
  56.  ***** Thanks to Markus Illenseer for some beta-testing.
  57.  *
  58.  *****    Function List :-
  59.  *
  60.  *    breakcheck()        by GD, modified by <HR>
  61.  *    __chkabort()        by <HR>
  62.  *    DoScsiCmd ()        by <HR>
  63.  *    err_str()        by GD
  64.  *    gcomp()            by GD
  65.  *    finddrivebrand()    by <HR>
  66.  *    GetDevName()        by GD
  67.  *    id2string ()        by <HR>
  68.  *    init ()            by GD, modified by <HR>
  69.  *    inquiry()        by GD, modified by <HR>
  70.  *    medium_removal()    by <HR>
  71.  *    mode_sense()        by <HR>
  72.  *    motor ()        by GD, modified by <HR>
  73.  *    play_audio ()        by <HR>
  74.  *    rawahexasciioutput()    by <HR>
  75.  *    rawhexoutput()        by <HR>
  76.  *    read_capacity()        by GD, modified by <HR>
  77.  *    read_cdblockheader()    by <HR>
  78.  *    read_cddaasync()    by <HR>
  79.  *    read_sec ()        by GD, modified by <HR>
  80.  *    read_sec_scsi ()    by GD, modified by <HR>
  81.  *    read_subchannel()    by <HR>
  82.  *    read_toc ()        by <HR>
  83.  *    seek ()            by GD, modified by <HR>
  84.  *    SendScsiCmd()        by <HR>
  85.  *    sense_errs()        by GD
  86.  *    set_volume()        by <HR>
  87.  *    usage()            by GD, modified by <HR>
  88.  *    WaitScsiCmd()        by <HR>
  89.  *
  90.  */
  91.  
  92. #define VERSION "2.0"
  93.  
  94. /*
  95.  **** Includes
  96.  */
  97. #include <stdio.h>
  98. #include <string.h>
  99. #include <ctype.h>
  100. #include <exec/types.h>
  101. #include <exec/io.h>
  102. #include <exec/execbase.h>
  103. #include <exec/nodes.h>
  104. #include <exec/memory.h>
  105. #include <devices/trackdisk.h>
  106. #include <devices/scsidisk.h>
  107. #include <libraries/dos.h>
  108. #ifdef __SASC
  109. #include <proto/all.h>
  110. #else
  111. #include <clib/alib_protos.h>
  112. #include <clib/exec_protos.h>
  113. /* non-ANSI C macro isascii() */
  114. #define isascii(a) (((a) & 0x80) == 0)
  115. #endif
  116. #include "scsi_priv.h"
  117.  
  118. /*
  119.  **** Global variables
  120.  */
  121. UBYTE *ip_buf = NULL;
  122. UBYTE *scsi_data = NULL;
  123. UBYTE *toc_buf = NULL;
  124.  
  125. UBYTE *dev = "";
  126.  
  127. int scsi_id = -1;        /* ID of the SCSI device to send commands to */
  128. UBYTE *pname;
  129. UBYTE buffer[LINE_BUF];
  130. int secno = -1;
  131. DRIVETYPE whatdrive = UNKNOWN;    /* what CD-ROM brand */
  132.  
  133. UBYTE *cdda_buf[NDBLBUF];
  134. MSGPORT *mp_ptr[NDBLBUF];
  135. IOSTDREQ *io_ptr[NDBLBUF];
  136. SCSICMD scsi_cmd[NDBLBUF];
  137. UBYTE *scsi_sense[NDBLBUF];
  138. UBYTE scsi_status[NDBLBUF];
  139. BYTE *mono_buf[NDBLBUF];
  140.  
  141. #ifdef USE8SVX
  142. BYTE write8svx = FALSE;        /* convert to 8SVX */
  143. #endif    /* USE8SVX */
  144.  
  145. /*
  146.  **** Function descr.
  147.  */
  148. int breakcheck (void);
  149. int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  150. UBYTE *err_str (int err);
  151. void exit (int status);
  152. void finddrivebrand (void);
  153. int gcomp (char *p1, char *p2, int len);
  154. UBYTE *GetDevName (char *grep);
  155. UBYTE *id2string (int id, IDTOSTRING * idtable);
  156. BOOLEAN init (void);
  157. void inquiry (BOOLEAN parsedoutput);
  158. void medium_removal(BOOLEAN lock);
  159. void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
  160. void motor (int motorstatus);
  161. void play_audio (int starttrack, int startindex, int endtrack, int endindex);
  162. void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
  163. void rawhexoutput (UBYTE *p, UWORD numbytes);
  164. void read_capacity (BOOLEAN parsed);
  165. void read_cdblockheader (BOOLEAN parsed, ULONG block);
  166. #ifdef _DCC
  167. __stkargs
  168. #endif
  169. void read_cddaasync (ULONG startblock, ULONG numblocks, BYTE
  170.              whichchannel, BYTE use16bit, unsigned int subcode);
  171. void read_sec (void);
  172. void read_sec_scsi (void);
  173. void read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track);
  174. void read_toc (int toclong);
  175. void seek (void);
  176. UBYTE *sense_errs (int req, int err);
  177. void set_volume (int vol0, int vol1, int vol2, int vol3);
  178. void usage (void);
  179.  
  180. int WaitScsiCmd (int req);
  181. void SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags);
  182.  
  183. #ifdef __SASC
  184. void __regargs __chkabort (void);
  185. #endif    /* __SASC */
  186. #ifdef _DCC
  187. #include <stdlib.h>
  188. typedef int (*brkfuncptr)();
  189. int brkhandler() { return(0); }
  190. #endif
  191.  
  192.  
  193.  
  194. /*********************************************************************
  195.  *
  196.  *    main
  197.  *
  198.  *
  199.  */
  200.  
  201. int
  202. main (int argc, char **argv)
  203. {
  204.   UBYTE *p;
  205.   int j = 0, i = 0;
  206.   int returnvalue = 0;
  207.  
  208. #ifdef _DCC
  209.   int (*oldbrkhandler)() = onbreak(brkhandler);
  210. #endif
  211.   if (argc == 1)
  212.     {
  213.       usage ();
  214.       exit (1);
  215.     }
  216.  
  217.   /*
  218.    *      see if a SCSI.device specified
  219.    */
  220.   if (strncmp (argv[1], "-d", 2) == 0)
  221.     {
  222.       j = 1;
  223.       dev = argv[1] + 2;
  224.     }
  225.   else if ((dev = GetDevName (SCSI_STRING)) == NULL)
  226.     {
  227.       fprintf (stderr, "Error : no *scsi*.device in device list\n");
  228.       exit (1);
  229.     }
  230.   pname = argv[0];
  231.   if (argc < (j + 2))
  232.     {
  233.       usage ();            /* help inquiry */
  234.       exit (1);
  235.     }
  236.  
  237.   if (argc < (j + 3))
  238.     {
  239.       fprintf (stderr, "Error : Not enough params\n");
  240.       exit (1);
  241.     }
  242.  
  243.   /*
  244.    *    pick up SCSI id ; do a rough check
  245.    */
  246.   if (sscanf (argv[j + 1], "%d", &scsi_id) != 1 || scsi_id < 0)
  247.     {
  248.       fprintf (stderr, "Error : Bad scsi id\n");
  249.       exit (1);
  250.     }
  251.  
  252.   if (*(p = argv[j + 2]) != '-')
  253.     {
  254.       fprintf (stderr, "Error : bad option\n");
  255.       exit (1);
  256.     }
  257.  
  258.   /*
  259.    *    now set up structures etc for SCSI xfer
  260.    */
  261.   if (init () == FALSE)
  262.     {
  263.       returnvalue = 1;
  264.       goto error;
  265.     }
  266.  
  267.  
  268.   /*
  269.    **********************    now examine the options
  270.    */
  271.   if (argc == (j + 3))
  272.     /* commands without parameter */
  273.     {
  274.       switch (*++p)
  275.     {
  276.       /*
  277.            ****     read capacity
  278.            */
  279.     case 'c':
  280.       if (*++p == 'r')
  281.         {
  282.               read_capacity (FALSE);    /* output raw data */
  283.             }
  284.           else
  285.             {
  286.               read_capacity (TRUE);    /* output parsed data */
  287.             }
  288.       break;
  289.  
  290.       /*
  291.            ****     inquiry (raw)
  292.            */
  293.     case 'i':
  294.       if (*++p == 'r')
  295.         {
  296.               inquiry (FALSE);        /* output raw data */
  297.             }
  298.           else
  299.             {
  300.               inquiry (TRUE);        /* output parsed data */
  301.             }
  302.       break;
  303.  
  304.       /*
  305.            ****     read TOC
  306.            */
  307.     case 't':
  308.       if (*(p+1) == 'r')
  309.         {
  310.           read_toc(0);    /* output raw data */
  311.         }
  312.       else if (*(p+1) == 'l')
  313.         {
  314.           read_toc(2);    /* output long form */
  315.         }
  316.       else
  317.         {
  318.               read_toc(1);    /* output short form */
  319.         }
  320.       break;
  321.  
  322.       /*
  323.            ****     show volume settings
  324.            */
  325.     case 'v':
  326.       set_volume (-1, -1, -1, -1);
  327.       break;
  328.  
  329.     default:
  330.       fprintf (stderr, "Error : bad option\n");
  331.       returnvalue = 3;
  332.     }
  333.     }
  334.   else if (argc == (j + 4))
  335.     /* commands with one parameter */
  336.     {
  337.       switch (*++p)
  338.     {
  339.       /*
  340.            ****     change medium
  341.            */
  342.     case 'e':
  343.       {
  344.         int eject = -1;
  345.             
  346.             if (sscanf (argv[j + 3], "%d", &eject) != 1
  347.                 || ((eject != 0) && (eject != 1)))
  348.               {
  349.                 fprintf (stderr, "Error : eject/load control must be 0 or 1\n");
  350.                 returnvalue = 3;
  351.               }
  352.             else
  353.               {
  354.                 motor ((eject | 2));    /* eject/insert */
  355.               }
  356.       }
  357.       break;
  358.  
  359.       /*
  360.            ****     read CD-ROM data block address header
  361.            */
  362.     case 'h':
  363.       {
  364.         ULONG block;
  365.  
  366.         if (sscanf (argv[j + 3], "%lu", &block) != 1)
  367.           {
  368.             fprintf (stderr, "Error : Bad block no\n");
  369.             returnvalue = 3;
  370.           }
  371.         else
  372.           {
  373.             if (*++p == 'r')
  374.               {
  375.                 read_cdblockheader (FALSE, block);
  376.               }
  377.             else
  378.               {
  379.                 read_cdblockheader (TRUE, block);
  380.               }
  381.           }
  382.       }
  383.       break;
  384.  
  385.       /*
  386.            ****     prevent/allow medium removal
  387.            */
  388.     case 'l':
  389.       {
  390.         int lock = -1;
  391.  
  392.             if (sscanf (argv[j + 3], "%d", &lock) != 1
  393.                || ((lock != 0) && (lock != 1)) )
  394.               {
  395.                 fprintf (stderr, "Error : Medium removal control must be 0 or 1\n");
  396.                 returnvalue = 3;
  397.               }
  398.             else
  399.               {
  400.                 medium_removal (lock);    /* prevent/allow medium removal */
  401.               }
  402.       }
  403.       break;
  404.  
  405.       /*
  406.            ****     stop/start motor
  407.            */
  408.     case 'm':
  409.       {
  410.         int motoronoff = -1;
  411.  
  412.             if (sscanf (argv[j + 3], "%d", &motoronoff) != 1
  413.                || ((motoronoff != 0) && (motoronoff != 1)) )
  414.               {
  415.                 fprintf (stderr, "Error : motor control must be 0 or 1\n");
  416.                 returnvalue = 3;
  417.               }
  418.             else
  419.               {
  420.                 motor (motoronoff);    /* turn on/off motor */
  421.               }
  422.       }
  423.       break;
  424.  
  425.       /*
  426.            ****     read sectors
  427.            */
  428.  
  429.     case 'r':
  430.       /*
  431.            *        get sector #
  432.            */
  433.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  434.         {
  435.           fprintf (stderr, "Error : Bad sec no\n");
  436.           returnvalue = 3;
  437.         }
  438.       else
  439.         {
  440.           if (*++p == 't')
  441.             {
  442.                   read_sec ();    /* read sector with trackdisk.device */
  443.             }
  444.           else
  445.             {
  446.                   read_sec_scsi ();    /* read sector with scsi */
  447.             }
  448.         }
  449.       break;
  450.  
  451.       /*
  452.            ****     seek to cylinder containing secno
  453.            */
  454.     case 's':
  455.       /*
  456.            *        get sector #
  457.            */
  458.       if (sscanf (argv[j + 3], "%d", &secno) != 1)
  459.         {
  460.           fprintf (stderr, "Error : Bad sec no\n");
  461.           returnvalue = 3;
  462.         }
  463.       else
  464.         {
  465.           seek ();
  466.         }
  467.       break;
  468.  
  469.     default:
  470.       fprintf (stderr, "Error : bad option\n");
  471.       returnvalue = 3;
  472.     }
  473.     }
  474.   else if (argc == (j + 5))
  475.     /* commands with two parameters */
  476.     {
  477.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  478.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  479.  
  480.       switch (*++p)
  481.     {
  482.       /*
  483.            ****     read CD-DA (8 bit left|right mono)
  484.            */
  485.     case 'D':
  486.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  487.           && whichchannel != 'R')
  488.         {
  489.           fprintf (stderr, "Error : must be either -DL or -DR\n");
  490.           returnvalue = 3;
  491.         }
  492.       else
  493.         {
  494.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  495.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  496.             {
  497.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  498.               returnvalue = 3;
  499.             }
  500.           else
  501.             {
  502.                   read_cddaasync (startblock, numblocks, whichchannel,
  503.                   FALSE, 0);
  504.             }
  505.         }
  506.       break;
  507.  
  508. #ifdef USE8SVX
  509.       /*
  510.            ****     read CD-DA (output 8SVX 8 bit left|right|stereo)
  511.            */
  512.     case '8':
  513.       if ((whichchannel = toupper (*(p + 1))) != 'L' && whichchannel != 'R' && whichchannel != 'S')
  514.         {
  515.           fprintf (stderr, "Error : must be -8{L|R|S}\n");
  516.           returnvalue = 3;
  517.         }
  518.       else
  519.         {
  520.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  521.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  522.             {
  523.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  524.             }
  525.           else
  526.             {
  527.                   write8svx = TRUE;
  528.                   read_cddaasync (startblock, numblocks, whichchannel,
  529.                   FALSE, 0);
  530.             }
  531.         }
  532.       break;
  533. #endif    /* USE8SVX */
  534.  
  535.       /*
  536.            ****     mode sense
  537.            */
  538.     case 'o':
  539.       {
  540.         int control, page;
  541.  
  542.             if (sscanf (argv[j + 3], "%d", &control) != 1 || control < 0 || control > 3)
  543.               {
  544.                 fprintf(stderr, "Error : invalid parameter for control (must be 0-4)\n");
  545.                 returnvalue = 3;
  546.               }
  547.             else
  548.               {
  549.                 if (sscanf (argv[j + 4], "%d", &page) != 1 || page < 0 || page > 0x3f)
  550.                   {
  551.                     fprintf(stderr, "Error : invalid parameter for page (must be 0-0x3f)\n");
  552.                     returnvalue = 3;
  553.                   }
  554.                 else
  555.                   {
  556.                     if (*++p == 'r')
  557.                       /* raw */
  558.                       {
  559.                         mode_sense (FALSE, control, page);
  560.                       }
  561.                     else
  562.                       /* parsed */
  563.                       {
  564.                         mode_sense (TRUE, control, page);
  565.                       }
  566.                   }
  567.               }
  568.       }
  569.           break;
  570.  
  571.  
  572.     default:
  573.       fprintf (stderr, "Error : bad option\n");
  574.       returnvalue = 3;
  575.     }
  576.     }
  577.   else if (argc == (j + 6))
  578.     /* commands with 3 parameters */
  579.     {
  580.       ULONG startblock, numblocks;    /* used by the CDDA commands */
  581.       BYTE whichchannel = -1;        /* read left / right channel / stereo */
  582.       unsigned int subcode = 0;
  583.  
  584.       switch (*++p)
  585.         {
  586.       /*
  587.            ****     read CD-DA (16 bit raw left|right|stereo)
  588.            */
  589.     case 'd':
  590.       if ((whichchannel = toupper (*(p + 1))) != 'L'
  591.           && whichchannel != 'R' && whichchannel != 'S')
  592.         {
  593.           fprintf (stderr, "Error : must be -d{L|R|S}\n");
  594.           returnvalue = 3;
  595.         }
  596.       else
  597.         {
  598.           if (sscanf (argv[j + 3], "%lu", &startblock) != 1
  599.               || sscanf (argv[j + 4], "%lu", &numblocks) != 1)
  600.             {
  601.               fprintf(stderr, "Error : invalid parameter for startblock of numblocks\n");
  602.               returnvalue = 3;
  603.             }
  604.           else
  605.             {
  606.           if (sscanf (argv[j + 5], "%u", &subcode) != 1)
  607.             {
  608.               fprintf(stderr, "Error : invalid parameter for subcode\n");
  609.               returnvalue = 3;
  610.             }
  611.           else
  612.             read_cddaasync (startblock, numblocks, whichchannel,
  613.                     TRUE, subcode);
  614.             }
  615.         }
  616.       break;
  617.  
  618.       /*
  619.            ****     read sub-channel information
  620.            */
  621.     case 'u':    /* raw */
  622.     case 'U':    /* parsed */
  623.       {
  624.         int trackno, subchannelformat, subchannel;
  625.  
  626.             /*
  627.              *        get sub-channel #
  628.              */
  629.             if (sscanf (argv[j + 3], "%d", &subchannel) != 1
  630.                 || subchannel < 0 || subchannel >255)
  631.               {
  632.                 fprintf (stderr, "Error : Sub-channel must be 0-255\n");
  633.                 returnvalue = 3;
  634.               }
  635.             /*
  636.              *        get sub-channel data format #
  637.              */
  638.             if (sscanf (argv[j + 4], "%d", &subchannelformat) != 1
  639.                 || subchannelformat < 0 || subchannelformat >255)
  640.               {
  641.                 fprintf (stderr, "Error : Sub-channel data format must be 0-255\n");
  642.                 returnvalue = 3;
  643.               }
  644.             /*
  645.              *        get track #
  646.              */
  647.             if (sscanf (argv[j + 5], "%d", &trackno) != 1 || trackno < 0
  648.                 || trackno > 99)
  649.               {
  650.                 fprintf (stderr, "Error : Bad track no (must be 1-99)\n");
  651.                 returnvalue = 3;
  652.               }
  653.             else
  654.               {
  655.                 if (*++p == 'r')
  656.                   {
  657.                     read_subchannel (FALSE,subchannel, subchannelformat, trackno);
  658.                   }
  659.                 else
  660.                   {
  661.                     read_subchannel (TRUE,subchannel, subchannelformat, trackno);
  662.                   }
  663.               }
  664.         }
  665.       break;
  666.  
  667.     default:
  668.       fprintf (stderr, "Error : bad option\n");
  669.       returnvalue = 3;
  670.     }
  671.  
  672.     }
  673.  
  674.   else if (argc == (j + 7))
  675.     /* commands with 4 parameters */
  676.     {
  677.       switch (*++p)
  678.     {
  679.       /*
  680.            ****     play audio
  681.            */
  682.     case 'p':
  683.       {
  684.         int starttrack, startindex, endtrack, endindex;
  685.  
  686.             if (sscanf (argv[j + 3], "%d", &starttrack) != 1
  687.                 || (starttrack < 1) || (starttrack > 99))
  688.               {
  689.                 fprintf (stderr, "Error : Starting audio track must be in the range 1-99\n");
  690.                 returnvalue = 3;
  691.                 goto error;
  692.               }
  693.             if (sscanf (argv[j + 4], "%d", &startindex) != 1
  694.                 || (startindex < 0) || (startindex > 99))
  695.               {
  696.                 fprintf (stderr, "Error : Starting audio track index must be in the range 1-99\n");
  697.                 returnvalue = 3;
  698.                 goto error;
  699.               }
  700.             if (sscanf (argv[j + 5], "%d", &endtrack) != 1
  701.                 || (endtrack < 1) || (endtrack > 99))
  702.               {
  703.                 fprintf (stderr, "Error : Ending audio track must be in the range 1-99\n");
  704.                 returnvalue = 3;
  705.                 goto error;
  706.               }
  707.             if (sscanf (argv[j + 6], "%d", &endindex) != 1
  708.                 || (endindex < 0) || (endindex > 99))
  709.               {
  710.                 fprintf (stderr, "Error : Ending audio track index must be in the range 1-99\n");
  711.                 returnvalue = 3;
  712.                 goto error;
  713.               }
  714.             play_audio (starttrack, startindex, endtrack, endindex);
  715.       }
  716.       break;
  717.  
  718.       /*
  719.            ****     change volume settings
  720.            */
  721.     case 'v':
  722.       {
  723.         int i;
  724.         int vol[4];
  725.  
  726.         for (i = 0; i < 4; i++)
  727.           {
  728.         if (sscanf (argv[j + 3 + i], "%d", &vol[i]) != 1
  729.             || (vol[i] < -1) || (vol[i] > 255))
  730.           {
  731.             fprintf (stderr, "Error : Volume %d must be in the range -1 - 255\n", i);
  732.             returnvalue = 3;
  733.             goto error;
  734.           }
  735.           }
  736.         set_volume (vol[0], vol[1], vol[2], vol[3]);
  737.       }
  738.       break;
  739.  
  740.     default:
  741.       fprintf (stderr, "Error : bad option\n");
  742.       returnvalue = 3;
  743.     }
  744.     }
  745.   else
  746.     {
  747.       fprintf (stderr, "Error : bad option\n");
  748.       returnvalue = 3;
  749.     }
  750.  
  751. error:
  752.  
  753.   for (i = 0; i < NDBLBUF; i++)
  754.     {
  755.       if (io_ptr[i])
  756.     {
  757.       CloseDevice ((struct IORequest *) io_ptr[i]);
  758.       DeleteStdIO (io_ptr[i]);
  759.     }
  760.  
  761.       if (cdda_buf[i])
  762.     FreeMem (cdda_buf[i], MAX_CDDALEN);
  763.  
  764.       if (mp_ptr[i])
  765.     DeletePort (mp_ptr[i]);
  766.  
  767.       if (scsi_sense[i])
  768.     FreeMem (scsi_sense[i], SENSE_LEN);
  769.  
  770.       if (mono_buf)
  771.     FreeMem (mono_buf[i], MAX_CDDALEN / 2);
  772.     }
  773.  
  774.   if (toc_buf)
  775.     FreeMem (toc_buf, MAX_TOC_LEN);
  776.  
  777.   if (ip_buf)
  778.     FreeMem (ip_buf, TD_SECTOR);
  779.  
  780.   if (scsi_data)
  781.     FreeMem (scsi_data, MAX_DATA_LEN);
  782.  
  783. #ifdef _DCC
  784.   onbreak(oldbrkhandler);
  785. #endif
  786.   exit (returnvalue);
  787. }
  788.  
  789. /*********************************************************************
  790.  *
  791.  *    Initialization function
  792.  *
  793.  */
  794. BOOLEAN
  795. init (void)
  796. {
  797.   int i;
  798.  
  799.   if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
  800.     {
  801.       fprintf (stderr, "AllocMem(0) Fail\n");
  802.       return FALSE;
  803.     }
  804.  
  805.   if ((ip_buf = (UBYTE *) AllocMem (TD_SECTOR, MEMF_CHIP)) == NULL)
  806.     {
  807.       fprintf (stderr, "AllocMem(2) Fail\n");
  808.       return FALSE;
  809.     }
  810.  
  811.   if ((toc_buf = (UBYTE *) AllocMem (MAX_TOC_LEN, MEMF_CHIP)) == NULL)
  812.     {
  813.       fprintf (stderr, "AllocMem(3) Fail\n");
  814.       return FALSE;
  815.     }
  816.  
  817.   for (i = 0; i < NDBLBUF; i++)
  818.     {
  819.       if ((scsi_sense[i] = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
  820.     {
  821.       fprintf (stderr, "AllocMem (scsi_sense[%d]) Fail\n",i);
  822.       return FALSE;
  823.     }
  824.       if ((cdda_buf[i] = (UBYTE *) AllocMem (MAX_CDDALEN, 0)) == NULL)
  825.     {
  826.       fprintf (stderr, "AllocMem (cdda_buf[%d]) Fail\n",i);
  827.       return FALSE;
  828.     }
  829.  
  830.       if ((mp_ptr[i] = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
  831.     {
  832.       fprintf (stderr, "CreatePort (mp_ptr[%d]) Fail\n",i);
  833.       return FALSE;
  834.     }
  835.       if ((io_ptr[i] = (IOSTDREQ *) CreateStdIO (mp_ptr[i])) == NULL)
  836.     {
  837.       fprintf (stderr, "CreateStdIO (io_ptr[%d]) Fail\n",i);
  838.       return FALSE;
  839.     }
  840.       if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr[i], 0) != 0)
  841.     {
  842.       fprintf (stderr,
  843.            "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
  844.            io_ptr[i]->io_Error, dev, scsi_id, i);
  845.       return FALSE;
  846.     }
  847.       if ((mono_buf[i] = (BYTE *) AllocMem (MAX_CDDALEN / 2, 0)) == NULL)
  848.     {
  849.       fprintf (stderr, "AllocMem (mono_buf[%d]) Fail\n",i);
  850.       return FALSE;
  851.     }
  852.  
  853.     }
  854.  
  855.   return TRUE;
  856. }
  857.  
  858. /*********************************************************************
  859.  *
  860.  *    function to read parameter pages from a device
  861.  */
  862.  
  863. void
  864. mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page)
  865. {
  866.   static SCSICMD6 command =
  867.   {
  868.     SCSI_CMD_MSE,    /* 0x1a MODE SENSE scsi command */
  869.     PAD,        /* LUN | rsrvd. | DBD | rsrvd. */
  870.     0,            /* PC | Page Code */
  871.     PAD,        /* rsrvd. */
  872.     0,            /* allocation length */
  873.     PAD            /* control */
  874.   };
  875.  
  876.   static IDTOSTRING pagecontrolfield[] =
  877.   {
  878.     0x00, "Current Values",
  879.     0x01, "Changeable Values",
  880.     0x02, "Default Values",
  881.     0x03, "Saved Values",
  882.     -1, "Illegal value"
  883.   };
  884.  
  885.   UWORD i,j;
  886.   int err;
  887.  
  888.   command.b2 = (control<<6) | page;
  889.   command.b4 = MAX_DATA_LEN;
  890.  
  891.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  892.                         (UBYTE *) &command, sizeof (command),
  893.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  894.     {
  895.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  896.     }
  897.   else
  898.     {
  899.       if (parsed == TRUE)
  900.         /* output parsed data */
  901.         {
  902.           printf ("%s\n", id2string(control, pagecontrolfield));
  903.           printf ("Mode Parameter Header:\n");
  904.           printf (" Mode Data Length: %hu\n", scsi_data[0]);
  905.           printf (" Medium Type: %hu\n", scsi_data[1]);
  906.           printf (" Device-Specific Parameter: %hu\n", scsi_data[2]);
  907.           printf (" Block Descriptor Length: %hu\n", scsi_data[3]);
  908.  
  909.       for (i = 0; i < scsi_data[3]; i +=8)    /* print block descriptors */
  910.         {
  911.           printf("Block Descriptor Density Code: %hu\n",scsi_data[(i)+4]);
  912.           printf(" Number of Blocks: %lu\n", (scsi_data[(i)+5]<<16) + (scsi_data[(i)+6]<<8) + (scsi_data[(i)+7]) );
  913.           printf(" Byte 4 (reserved): %hu\n", scsi_data[(i)+8]);
  914.           printf(" Block length: %lu\n", (scsi_data[(i)+9]<<16) + (scsi_data[(i)+10]<<8) + (scsi_data[(i)+11]) );
  915.         }
  916.  
  917.       for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  918.         {
  919.           printf("Page Code: %hu\n",scsi_data[i] & 0x3f);
  920.           printf(" Page can%s be saved\n", (scsi_data[i] & 0x80) ? "" : " not");
  921.           printf(" Page Length: %hu\n", scsi_data[i+1]);
  922.           printf(" Mode Parameters:\n");
  923.           rawhexasciioutput(&scsi_data[i+2], scsi_data[i+1], 2);
  924.         }
  925.         }
  926.       else
  927.         /* output raw data */
  928.         {
  929.           rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
  930.         }
  931.     }
  932. }
  933.  
  934. /*********************************************************************
  935.  *
  936.  *    function to read CD-ROM data block address header
  937.  *    starting block and number of blocks.
  938.  */
  939.  
  940. void
  941. read_cdblockheader (BOOLEAN parsed, ULONG block)
  942. {
  943.   static SCSICMD10 command =
  944.   {
  945.     SCSI_CMD_READHEADER,    /* 0x44 READ HEADER scsi command */
  946.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  947.     0, 0, 0, 0,            /* Logical Block Address (ULONG) */
  948.     PAD,            /* reserved */
  949.     0,0,            /* allocated data length */
  950.     PAD                /* control */
  951.   };
  952.  
  953.   static IDTOSTRING udatafieldcont[] =
  954.   {
  955.     0x00, "All bytes zero",
  956.     0x01, "User Data",
  957.     0x02, "User Data",
  958.     -1, "Reserved"
  959.   };
  960.  
  961.   static IDTOSTRING auxfieldcont[] =
  962.   {
  963.     0x00, "All bytes zero",
  964.     0x01, "L-EC symbols",
  965.     0x02, "User Data",
  966.     -1, "Reserved"
  967.   };
  968.  
  969.   int err;
  970.  
  971.   command.b2 = block>>24;
  972.   command.b3 = block>>16;
  973.   command.b4 = block>>8;
  974.   command.b5 = block;
  975. #if MAX_CDDALEN > 65536
  976.   command.b7 = 255;
  977.   command.b8 = 255;
  978. #else
  979.   command.b7 = MAX_CDDALEN>>8;
  980.   command.b8 = MAX_CDDALEN & 0xff;
  981. #endif
  982.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  983.                         (UBYTE *) &command, sizeof (command),
  984.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  985.     {
  986.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  987.     }
  988.   else
  989.     {
  990.       if (parsed == TRUE)
  991.         {
  992.           printf("User Data Field Contents (2048 bytes): %d = %s\n",
  993.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], udatafieldcont));
  994.           printf("Auxiliary Field Contents ( 288 bytes): %d = %s\n",
  995.          (cdda_buf[0])[0], id2string ((cdda_buf[0])[0], auxfieldcont));
  996.           printf("Byte 1 (reserved): %d\n",(cdda_buf[0])[1]);
  997.           printf("Byte 2 (reserved): %d\n",(cdda_buf[0])[2]);
  998.           printf("Byte 3 (reserved): %d\n",(cdda_buf[0])[3]);
  999.           printf("Absolute CD-ROM Address: %lu\n",
  1000.          ((cdda_buf[0])[4] << 24) | ((cdda_buf[0])[5] << 16) | ((cdda_buf[0])[6] << 8) | ((cdda_buf[0])[7]));
  1001.         }
  1002.       else
  1003.         {
  1004.           rawhexasciioutput(cdda_buf[0], 8, 0);
  1005.         }
  1006.     }
  1007. }
  1008.  
  1009. /*********************************************************************
  1010.  *
  1011.  *    function to read subchannel data audio from Sony CDROM with
  1012.  *    starting block and number of blocks.
  1013.  */
  1014.  
  1015. void
  1016. read_subchannel (BOOLEAN parsed, UBYTE subchannel, UBYTE subchannelformat, UBYTE track)
  1017. {
  1018.   static SCSICMD10 command =
  1019.   {
  1020.     SCSI_CMD_READSUBCHANNEL,    /* 0x42 READ SUB-CHANNEL scsi command */
  1021.     0,                /* LUN | rsrvd. | MSF | rsrvd. */
  1022.     0x40,            /* return Sub-Q Channel data */
  1023.     0,                /* Sub-channel Data Format */
  1024.     PAD,
  1025.     PAD,
  1026.     0,                /* Track Number 1-99 */
  1027.     0,0,            /* allocated data length */
  1028.     PAD                /* control */
  1029.   };
  1030.  
  1031.   static IDTOSTRING audiostatus[] =
  1032.   {
  1033.     0x00, "Audio status byte not supported or not valid",
  1034.     0x11, "Audio play operation in progress.",
  1035.     0x12, "Audio play operation paused.",
  1036.     0x13, "Audio play operation successfully completed.",
  1037.     0x14, "Audio play operation stopped due to error.",
  1038.     0x15, "No current audio status to return",
  1039.     -1, "Reserved, unknown or no audio status"
  1040.   };
  1041.  
  1042.   static IDTOSTRING Qfield[] =
  1043.   {
  1044.     0x00, "Sub-channel Q mode information not supplied.",
  1045.     0x01, "Sub-channel Q encodes current position data.",
  1046.     0x02, "Sub-channel Q encodes media catalog number.",
  1047.     0x03, "Sub-channel Q encodes ISRC.",
  1048.     -1, "Reserved"
  1049.   };
  1050.  
  1051.   int err;
  1052.  
  1053.   command.b2 = subchannel;
  1054.   command.b3 = subchannelformat;
  1055.   command.b6 = track;
  1056.  
  1057. #if MAX_CDDALEN > 65536
  1058.   command.b7 = 255;
  1059.   command.b8 = 255;
  1060. #else
  1061.   command.b7 = MAX_CDDALEN & 0xff;
  1062.   command.b8 = MAX_CDDALEN>>8;    /* Allocation length = max. data length */
  1063. #endif
  1064.  
  1065.   if ((err = DoScsiCmd ((UBYTE *) cdda_buf[0], MAX_CDDALEN,
  1066.                         (UBYTE *) &command, sizeof (command),
  1067.                         (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1068.     {
  1069.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1070.     }
  1071.   else
  1072.     {
  1073.       if (parsed == TRUE)
  1074.         /* parsed output */
  1075.         {
  1076.           if (subchannel == 0x40)
  1077.             {
  1078.               if (subchannelformat == 0)
  1079.                 {
  1080.     /* CHANGE - this doesn't work with my Apple CD300!!!!! */
  1081.           rawhexoutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4);
  1082.                 }
  1083.               else if (subchannelformat == 1)
  1084.                 {
  1085.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1086.           printf("Audio status: %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1087.           printf("Sub-Channel Data Length: %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1088.           printf("Sub-Channel Data Format code (should be 0x01!): %d\n",(cdda_buf[0])[4]);
  1089.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f), Qfield));
  1090.  
  1091.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1092.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1093.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1094.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1095.  
  1096.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1097.           printf("Index Number: %d\n", (cdda_buf[0])[7]);
  1098.           printf("Absolute CD-ROM Address: %lu\n", ((cdda_buf[0])[8] << 24) | ((cdda_buf[0])[9] << 16) | ((cdda_buf[0])[10] << 8) | ((cdda_buf[0])[11]));
  1099.           printf("Track Relative CD-ROM Address: %lu\n", ((cdda_buf[0])[12] << 24) | ((cdda_buf[0])[13] << 16) | ((cdda_buf[0])[14] << 8) | ((cdda_buf[0])[15]));
  1100.                 }
  1101.               else if (subchannelformat == 2)
  1102.                 {
  1103.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1104.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1105.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1106.           printf("Sub-Channel Data Format code (should be 0x02!): %d\n",(cdda_buf[0])[4]);
  1107.           printf("Byte 5 (reserved): %02x\n",(cdda_buf[0])[5]);
  1108.           printf("Byte 6 (reserved): %02x\n",(cdda_buf[0])[6]);
  1109.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1110.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1111.           printf("MCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1112.           printf("Media Catalog Number (UPC/Bar Code):\n");
  1113.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1114.                 }
  1115.               else if (subchannelformat == 3)
  1116.                 {
  1117.           printf("Byte 0 (reserved): %02x\n",(cdda_buf[0])[0]);
  1118.           printf("Audio status %s\n",id2string ((cdda_buf[0])[1],audiostatus));
  1119.           printf("Sub-Channel Data Length %d\n",((cdda_buf[0])[2]*256 + (cdda_buf[0])[3]));
  1120.           printf("Sub-Channel Data Format code (should be 0x03!): %d\n",(cdda_buf[0])[4]);
  1121.           printf("ADR: %s\n",id2string(((cdda_buf[0])[5]>>4 & 0x0f) ,Qfield));
  1122.  
  1123.           printf("Audio with%s pre-emphasis.  ", ((cdda_buf[0])[5] & 0x01) ? "" : "out");
  1124.           printf("Digital copy %s\n", ((cdda_buf[0])[5] & 0x02) ? "permitted" : "prohibited");
  1125.           printf("%s track.  ", ((cdda_buf[0])[5] & 0x04) ? "Data" : "Audio");
  1126.           printf("%s channel audio.\n", ((cdda_buf[0])[5] & 0x08) ? "Four" : "Two");
  1127.  
  1128.           printf("Track Number: %d\n", (cdda_buf[0])[6]);
  1129.           printf("Byte 7 (reserved): %02x\n",(cdda_buf[0])[7]);
  1130.           printf("Byte 8 (reserved): %02x\n",(cdda_buf[0])[8] & 0x7f);
  1131.           printf("TCVal is %s\n", ((cdda_buf[0])[8] & 0x80) ? "true" : "false");
  1132.           printf("Track International-Standard-Recording-Code (ISRC):\n");
  1133.           rawhexasciioutput(&(cdda_buf[0])[9], 15, 1);
  1134.                 }
  1135.               else
  1136.                 {
  1137.                   rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1138.                 }
  1139.             }
  1140.           else
  1141.             {
  1142.               rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1143.             }
  1144.         }
  1145.       else
  1146.         /* raw output */
  1147.         {
  1148.       rawhexasciioutput(cdda_buf[0], ((cdda_buf[0])[2]*256 + (cdda_buf[0])[3])+4, 0);
  1149.         }
  1150.     }
  1151.  
  1152. }
  1153.  
  1154. /*********************************************************************
  1155.  *
  1156.  * subroutine used to printout raw hex data bytes
  1157.  *
  1158.  */
  1159. void
  1160. rawhexoutput (UBYTE *p, UWORD numbytes)
  1161. {
  1162.   UWORD i;
  1163.  
  1164.   for (i = 0; i < numbytes; i++)
  1165.     {
  1166.       printf (" %02x", p[i]);
  1167.     }
  1168.   printf ("\n");
  1169. }
  1170.  
  1171. /*********************************************************************
  1172.  *
  1173.  * subroutine used to printout raw hex data bytes with the
  1174.  * corresponding ASCII values and an index
  1175.  *
  1176.  */
  1177. void
  1178. rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
  1179. {
  1180.   UWORD i, j;
  1181.   UBYTE *boff, *aoff;
  1182.   int xxxlen = strlen (" xx");            /* byte */
  1183.  
  1184.   buffer[5+leadspace] = '=';
  1185.  
  1186.   for (i = 0; i < numbytes; i += BYTES_PER_LINE)
  1187.     {
  1188.       memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1189.       boff = &buffer[7+leadspace];
  1190.       aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
  1191.  
  1192.       sprintf (buffer+leadspace, "%04X = ", i);        /* add offset */
  1193.  
  1194.       for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
  1195.         {
  1196.           sprintf (boff, " %02X", *p);
  1197.           *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
  1198.         }
  1199.  
  1200.       buffer[strlen (buffer)] = ' ';
  1201.       *++aoff = '\n';
  1202.       *++aoff = '\0';
  1203.       printf ("%s", buffer);
  1204.     }
  1205. }
  1206.  
  1207. /*********************************************************************
  1208.  *
  1209.  *    function to read digital audio from Sony / Toshiba CD-ROM with
  1210.  *    starting block and number of blocks.
  1211.  *    This version uses asynchronous reads.
  1212.  *
  1213.  *    outputs LRLRLR pairs of 16 bit digital stereo audio samples,
  1214.  *    2352 / 2368 / 2448 / 96 bytes per CD-ROM block
  1215.  *
  1216.  *      or (depending on 'whichchannel')
  1217.  *
  1218.  *      8 bit digital audio samples, either the left or right channel.
  1219.  */
  1220.  
  1221. #ifdef _DCC
  1222. __stkargs
  1223. #endif
  1224. void
  1225. read_cddaasync (ULONG startblock, ULONG numblocks, BYTE whichchannel,
  1226.         BYTE use16bit, unsigned int subcode)
  1227. {
  1228.   static struct CMD_RDCDDA
  1229.   {
  1230.     UBYTE cmd;            /* READ CD-DA scsi command 0xD8 */
  1231.     UBYTE pad_a;        /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1232.     ULONG lba;            /* logical block address MSB, , ,LSB */
  1233.     ULONG lbn;            /* number of blocks to transfer MSB, , ,LSB */
  1234.     UBYTE subcode;        /* special sub code selector:
  1235.                       * 0: normal 2352
  1236.                  * 1: 2368
  1237.                  * 2: 2448
  1238.                  * 3: 96 bytes */
  1239.     UBYTE cntrl;        /* Control */
  1240.   } command[NDBLBUF];
  1241.  
  1242.   /*
  1243.    * TOSHIBA XM3401 specific
  1244.    */
  1245.   static SCSICMD6 modecommand;
  1246.   static struct cddamodedata
  1247.   {
  1248.     UWORD pad0;
  1249.     UBYTE pad1;
  1250.     UBYTE bdlength;
  1251.     ULONG density;   /* = densitycode << 24 */
  1252.     ULONG blocklen;
  1253.   } newmodedata;
  1254.  
  1255.  
  1256.   int err, i = 0, j = 0, k = 0, l = 0;
  1257.   ULONG nblocks = numblocks, xblocks;
  1258.  
  1259.   finddrivebrand();        /* determine CD-ROM drive */
  1260.  
  1261.   /*
  1262.    * TOSHIBA XM3401 specific
  1263.    */
  1264.   if (whatdrive == TOSHIBA3401)
  1265.     {
  1266.       /* Read old mode data */
  1267.       modecommand.opcode  = SCSI_CMD_MSE;
  1268.       modecommand.b1      = 0;
  1269.       modecommand.b2      = 1;
  1270.       modecommand.b3      = 0;
  1271.       modecommand.b4      = MAX_DATA_LEN;
  1272.       modecommand.control = 0;
  1273.       if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1274.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1275.                 (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1276.     {
  1277.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1278.       return;
  1279.     }
  1280.       /* Write new mode data */
  1281.       newmodedata.pad0     = 0;
  1282.       newmodedata.pad1     = 0;
  1283.       newmodedata.bdlength = 8;
  1284.       newmodedata.density  = 0x82L << 24;
  1285.       newmodedata.blocklen = 2352;
  1286.       modecommand.opcode = SCSI_CMD_MSL;
  1287.       modecommand.b1     = 0x10;
  1288.       modecommand.b2     = 0;
  1289.       modecommand.b4     = sizeof(struct cddamodedata);
  1290.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1291.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1292.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1293.     {
  1294.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1295.       return;
  1296.     }
  1297.     } /* TOSHIBA */
  1298.  
  1299.   /* reset SCSI status to no command pending
  1300.    */
  1301.   for (i = 0; i < NDBLBUF; i++)
  1302.     scsi_status[i] = 0;
  1303.  
  1304.   for (i = 0; ; (++i >= NDBLBUF)? i = 0 : i)
  1305.     {
  1306.       if (breakcheck ())    /* ^C ? */
  1307.     {
  1308.       /* wait for pending SCSI commands
  1309.        */
  1310.       for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1311.         {
  1312.           if (scsi_status[i] == 1)
  1313.         WaitScsiCmd(i);
  1314.         }
  1315.       return;
  1316.     }
  1317.       if (nblocks > 0)
  1318.     {
  1319.       if (scsi_status[i] == 1)    /* SCSI command pending? */
  1320.         {
  1321.           if ((err = WaitScsiCmd (i)) != 0)    /* read failed, reschedule */
  1322.         {
  1323.           scsi_status[i] = 0;
  1324.           do
  1325.             {
  1326.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1327.  
  1328.               if (breakcheck ())    /* ^C ? */
  1329.             {
  1330.               for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1331.                 {
  1332.                   if (scsi_status[i] == 1)
  1333.                 WaitScsiCmd(i);
  1334.                 }
  1335.               return;
  1336.             }
  1337.               
  1338.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1339.                    (UBYTE *) & command[i], sizeof (command[i]),
  1340.                    (SCSIF_READ | SCSIF_AUTOSENSE));
  1341.             }
  1342.           while ((err = WaitScsiCmd (i)) != 0);
  1343.         }
  1344.           scsi_status[i] = 0;    /* no SCSI command pending anymore */
  1345.  
  1346.           if (use16bit == TRUE && whichchannel == 'S')
  1347.         /* output 16 bit stereo samples */
  1348.         {
  1349.           fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1350.         }
  1351.           else if (whichchannel == 'L')
  1352.         /* output left channel */
  1353.         {
  1354.           if (use16bit == FALSE)
  1355.             /* output raw 8 bit left channel */
  1356.             {
  1357.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1358.             {
  1359.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1360.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1361.             }
  1362.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1363.             }
  1364.           else
  1365.             /* output raw 16 bit left channel */
  1366.             {
  1367.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1368.             {
  1369.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1370.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1371.             }
  1372.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1373.             }
  1374.         }
  1375.           else
  1376.         /* output right channel */
  1377.         {
  1378.           if (use16bit == FALSE)
  1379.             /* output raw 8 bit left channel */
  1380.             {
  1381.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1382.             {
  1383.               (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1384.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1385.             }
  1386.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1387.             }
  1388.           else
  1389.             /* output raw 16 bit left channel */
  1390.             {
  1391.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1392.             {
  1393.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1394.               (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1395.             }
  1396.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1397.             }
  1398.         }
  1399.         }    /* (scsi_status[i] == 1) ? */
  1400.  
  1401.       if (whatdrive == TOSHIBA3401)
  1402.             {
  1403.               command[i].cmd = SCSI_CMD_READ12;   /* TOSHIBA XM3401 */
  1404.             }
  1405.       else
  1406.         {
  1407.               command[i].cmd = SCSI_CMD_READCDDA; /* Sony CDU-5*1 */
  1408.             }
  1409.           command[i].pad_a = 0;
  1410.           command[i].lba = startblock;
  1411.           command[i].lbn = xblocks = (nblocks > NUM_OF_CDDAFRAMES)? NUM_OF_CDDAFRAMES : nblocks;
  1412.       command[i].subcode = subcode;
  1413.       command[i].cntrl = 0;
  1414.  
  1415.       startblock += xblocks;
  1416.       nblocks -= xblocks;
  1417.  
  1418.       scsi_status[i] = 1;    /* Status: SCSI command pending */
  1419.  
  1420.       SendScsiCmd (i, (UBYTE *) cdda_buf[i], MAX_CDDALEN,
  1421.                (UBYTE *) & command[i], sizeof (command[i]),
  1422.                (SCSIF_READ | SCSIF_AUTOSENSE));
  1423.  
  1424.     }
  1425.       else    /* nblocks <= 0 */
  1426.     {
  1427.       /* wait for all pending requests */
  1428.       for (l = 0; l < NDBLBUF; l++)
  1429.         {
  1430.           if (scsi_status[i] == 1)    /* SCSI command pending ? */
  1431.         {
  1432.           if ((err = WaitScsiCmd (i)) != 0) /* SCSI command failed? */
  1433.             {
  1434.               scsi_status[i] = 0;
  1435.               do    /* reschedule SCSI command */
  1436.             {
  1437.               fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1438.  
  1439.               if (breakcheck ()) /* ^C ? */
  1440.                 {
  1441.                   /* wait for pending SCSI commands
  1442.                    */
  1443.                   for (j = 0, i++; j < NDBLBUF; j++, (++i >= NDBLBUF)? i = 0 : i)
  1444.                 {
  1445.                   if (scsi_status[i] == 1)
  1446.                     WaitScsiCmd(i);
  1447.                 }
  1448.                   return;
  1449.                 }
  1450.               
  1451.               SendScsiCmd (i, (UBYTE *) cdda_buf[i], scsi_cmd[i].scsi_Length,
  1452.                        (UBYTE *) & command[i], sizeof (command[i]),
  1453.                        (SCSIF_READ | SCSIF_AUTOSENSE));
  1454.               
  1455.             }
  1456.               while ((err = WaitScsiCmd (i)) != 0);
  1457.             }
  1458.           scsi_status[i] = 0;    /* Status: no SCSI command pending */
  1459.  
  1460.           if (use16bit == TRUE && whichchannel == 'S')
  1461.             /* output 16 bit stereo samples */
  1462.             {
  1463.               fwrite (cdda_buf[i], scsi_cmd[i].scsi_Actual, 1, stdout);
  1464.             }
  1465.           else if (whichchannel == 'L')
  1466.             /* output left channel */
  1467.             {
  1468.               if (use16bit == FALSE)
  1469.             /* output raw 8 bit left channel */
  1470.             {
  1471.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1472.                 {
  1473.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j)] +
  1474.                               ((cdda_buf[i])[(4 * j) + 1] * 256)) / 256);
  1475.                 }
  1476.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1477.             }
  1478.               else
  1479.             /* output raw 16 bit left channel */
  1480.             {
  1481.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1482.                 {
  1483.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j]);
  1484.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 1]);
  1485.                 }
  1486.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1487.             }
  1488.             }
  1489.           else
  1490.             /* output right channel */
  1491.             {
  1492.               if (use16bit == FALSE)
  1493.             /* output raw 8 bit left channel */
  1494.             {
  1495.               for (j = 0; j < (scsi_cmd[i].scsi_Actual / 4); j++)
  1496.                 {
  1497.                   (mono_buf[i])[j] = (BYTE) (((cdda_buf[i])[(4 * j) + 2] +
  1498.                               ((cdda_buf[i])[(4 * j) + 3] * 256)) / 256);
  1499.                 }
  1500.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 4), 1, stdout);
  1501.             }
  1502.               else
  1503.             /* output raw 16 bit left channel */
  1504.             {
  1505.               for (j = 0, k = 0; j < (scsi_cmd[i].scsi_Actual); j += 4)
  1506.                 {
  1507.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 2]);
  1508.                   (mono_buf[i])[k++] = (BYTE) ((cdda_buf[i])[j + 3]);
  1509.                 }
  1510.               fwrite (mono_buf[i], (scsi_cmd[i].scsi_Actual / 2), 1, stdout);
  1511.             }
  1512.             }        /* output right channel */
  1513.  
  1514.           scsi_status[i] = 0;
  1515.  
  1516.         }    /* (scsi_status[i] == 1) ? */
  1517.  
  1518.           (++i >= NDBLBUF)? i = 0 : i;
  1519.  
  1520.         }  /* for (l = 0; l < NDBLBUF; l++) */
  1521.  
  1522.       break;
  1523.     }
  1524.     }
  1525.   if (whatdrive == TOSHIBA3401)
  1526.     {
  1527.       /*
  1528.        * TOSHIBA XM3401 specific
  1529.        */
  1530.       /* Write old mode data */
  1531.       newmodedata.density  = ((struct cddamodedata *) scsi_data)->density;
  1532.       newmodedata.blocklen = ((struct cddamodedata *) scsi_data)->blocklen;
  1533.       if ((err = DoScsiCmd ((UBYTE *) &newmodedata, sizeof(struct cddamodedata),
  1534.                 (UBYTE *) &modecommand, sizeof (modecommand),
  1535.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  1536.     {
  1537.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1538.     }
  1539.     }
  1540. }
  1541.  
  1542. /*********************************************************************
  1543.  *
  1544.  *    function to read sectors from a starting sector #
  1545.  *    - similar adjacent lines are suppressed on printout.
  1546.  *
  1547.  *    - uses trackdisk.device
  1548.  */
  1549.  
  1550. void
  1551. read_sec (void)
  1552.  
  1553. {
  1554.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1555.   UBYTE *pref;
  1556.   UBYTE *p;
  1557.   UWORD j;
  1558.   UWORD k;
  1559.   int err;
  1560.  
  1561.   /*
  1562.    *  keep printing sectors until ^C , or until error
  1563.    */
  1564.   io_ptr[0]->io_Command = CMD_READ;
  1565.   io_ptr[0]->io_Length = TD_SECTOR;
  1566.   io_ptr[0]->io_Data = (APTR) ip_buf;
  1567.   io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* will be updated... */
  1568.  
  1569.  
  1570.   /*
  1571.    *  keep reading sectors : stop on ^C on bad sector #
  1572.    */
  1573.   for (;; ++secno)
  1574.     {
  1575.       UBYTE *ss;
  1576.       UWORD m_sec_offs;
  1577.  
  1578.       if (breakcheck ())    /* ^C ? */
  1579.     break;
  1580.  
  1581.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1582.  
  1583.       DoIO ((struct IORequest *) io_ptr[0]);
  1584.       if ((err = io_ptr[0]->io_Error) == 0)
  1585.     {
  1586.       printf ("\n");
  1587.       /*
  1588.        * scan this sector ...
  1589.         */
  1590.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1591.            m_sec_offs < TD_SECTOR;
  1592.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1593.         {
  1594.           int xxxlen = strlen (" xx");    /* byte */
  1595.  
  1596.           /*
  1597.            * don't print line if same contents as previous
  1598.            */
  1599.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1600.         {
  1601.           if (m_sec_offs > 1)
  1602.             continue;    /* same */
  1603.         }
  1604.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1605.  
  1606.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1607.  
  1608.           /* set up for loop */
  1609.  
  1610.           k = strlen (buffer);
  1611.           ss = buffer + k;
  1612.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1613.           for (p = sec_click_ptr, j = 0;
  1614.            j < BYTES_PER_LINE;
  1615.            ss += xxxlen, ++j, ++k)
  1616.         {
  1617.           UBYTE dd = *p++;
  1618.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1619.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1620.           buffer[k] = que;
  1621.         }
  1622.  
  1623.           buffer[strlen (buffer)] = ' ';
  1624.           buffer[k++] = '\n';
  1625.           buffer[k++] = '\0';
  1626.  
  1627.           printf ("%s", buffer);
  1628.           pref = sec_click_ptr;
  1629.  
  1630.         }
  1631.     }
  1632.       else
  1633.     {
  1634.       /* else DoIO error */
  1635.  
  1636.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1637.            err, secno, secno, sense_errs (0, err));
  1638.  
  1639.       return;
  1640.     }
  1641.     }
  1642. }
  1643.  
  1644. /*********************************************************************
  1645.  *
  1646.  *    function to read sectors from a starting sector #
  1647.  *    - similar adjacent lines are suppressed on printout.
  1648.  *
  1649.  *    - uses scsi device directly
  1650.  */
  1651.  
  1652. void
  1653. read_sec_scsi (void)
  1654. {
  1655.   static struct CMD_XREAD
  1656.   {
  1657.     UBYTE cmd;
  1658.     UBYTE lba[3];
  1659.     UBYTE numb_secs;
  1660.     UBYTE pad;
  1661.   } command =
  1662.   {
  1663.     SCSI_CMD_RD,
  1664.     0, 0, 0,
  1665.     0,
  1666.     PAD
  1667.   };
  1668.  
  1669.   UBYTE *sec_click_ptr;        /* click = 16 bytes    */
  1670.   UBYTE *pref;
  1671.   UBYTE *p;
  1672.   UWORD j;
  1673.   UWORD k;
  1674.   int err;
  1675.  
  1676.   /*
  1677.    *  keep printing sectors until ^C , or until error
  1678.    */
  1679.  
  1680.  
  1681.   /*
  1682.    *  keep reading sectors : stop on ^C on bad sector #
  1683.    */
  1684.   for (;; ++secno)
  1685.     {
  1686.       UBYTE *ss;
  1687.       UWORD m_sec_offs;
  1688.  
  1689.       command.lba[2] = secno;
  1690.       command.lba[1] = secno >> 8;
  1691.       command.lba[0] = (secno >> 8) & 0x1F;
  1692.  
  1693.       command.numb_secs = 1;
  1694.  
  1695.       if (breakcheck ())    /* ^C ? */
  1696.     break;
  1697.  
  1698.       io_ptr[0]->io_Offset = secno * TD_SECTOR;    /* sector offset */
  1699.  
  1700.       if ((err = DoScsiCmd ((UBYTE *) ip_buf, 512,
  1701.                 (UBYTE *) & command, sizeof (command),
  1702.                 (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1703.     {
  1704.       printf ("\n");
  1705.       /*
  1706.        * scan this sector ...
  1707.         */
  1708.       for (sec_click_ptr = pref = ip_buf, m_sec_offs = 0;
  1709.            m_sec_offs < TD_SECTOR;
  1710.            m_sec_offs += BYTES_PER_LINE, sec_click_ptr += BYTES_PER_LINE)
  1711.         {
  1712.           int xxxlen = strlen (" xx");    /* byte */
  1713.  
  1714.           /*
  1715.            * don't print line if same contents as previous
  1716.            */
  1717.           if (gcomp (sec_click_ptr, pref, BYTES_PER_LINE) == TRUE)
  1718.         {
  1719.           if (m_sec_offs > 1)
  1720.             continue;    /* same */
  1721.         }
  1722.           memset (buffer, ' ', sizeof (buffer));    /* put spaces in buffer */
  1723.  
  1724.           sprintf (buffer, "%05X:%03X = ", secno, m_sec_offs);
  1725.  
  1726.           /* set up for loop */
  1727.  
  1728.           k = strlen (buffer);
  1729.           ss = buffer + k;
  1730.           k += (BYTES_PER_LINE * xxxlen) + 1;
  1731.           for (p = sec_click_ptr, j = 0;
  1732.            j < BYTES_PER_LINE;
  1733.            ss += xxxlen, ++j, ++k)
  1734.         {
  1735.           UBYTE dd = *p++;
  1736.           UBYTE que = (isascii (dd) && isprint (dd)) ? dd : '.';
  1737.           sprintf (ss, " %02X", dd);    /* 2 hex charas  */
  1738.           buffer[k] = que;
  1739.         }
  1740.  
  1741.           buffer[strlen (buffer)] = ' ';
  1742.           buffer[k++] = '\n';
  1743.           buffer[k++] = '\0';
  1744.  
  1745.           printf ("%s", buffer);
  1746.           pref = sec_click_ptr;
  1747.  
  1748.         }
  1749.     }
  1750.       else
  1751.     {
  1752.       /* else DoIO error */
  1753.  
  1754.       fprintf (stderr, "Error :  sec = %ld dec , $%lX , [%s]\n",
  1755.            secno, secno, sense_errs (0, err));
  1756.       return;
  1757.     }
  1758.     }
  1759. }
  1760.  
  1761. /*********************************************************************
  1762.  *
  1763.  *    function to prevent/allow allow medium removal
  1764.  *
  1765.  */
  1766.  
  1767. void
  1768.  
  1769. medium_removal(int lock)
  1770. {
  1771.   static SCSICMD6 command =
  1772.   {
  1773.     SCSI_CMD_PAMR,        /* 0x1E SCSI Prevent Allow Medium Removal */
  1774.     0,                /* Bit 765 = LUN */
  1775.     PAD,            /* reserved */
  1776.     PAD,            /* reserved */
  1777.     0,                /* Bit 0 = prevent */
  1778.     PAD,            /* reserved */
  1779.   };
  1780.  
  1781.   int err;
  1782.  
  1783.   command.b4 = lock;
  1784.  
  1785.   if ((err = DoScsiCmd (0, 0,
  1786.             (UBYTE *) & command, sizeof (command),
  1787.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1788.     {
  1789.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1790.     }
  1791. }
  1792.  
  1793. /*********************************************************************
  1794.  *
  1795.  *    function to stop/start motor on SCSI device
  1796.  *    or eject/insert a medium
  1797.  *
  1798.  */
  1799.  
  1800. void
  1801. motor (int motorstatus)
  1802. {
  1803.   static SCSICMD6 command =
  1804.   {
  1805.     SCSI_CMD_SSU,        /* 0x1B SCSI Start / Stop Unit */
  1806.     0,
  1807.     PAD,
  1808.     PAD,
  1809.     0,                /* start/stop eject/insert */
  1810.     PAD,
  1811.   };
  1812.  
  1813.   int err;
  1814.  
  1815.   command.b4 = motorstatus;
  1816.  
  1817.   if ((err = DoScsiCmd (0, 0,
  1818.             (UBYTE *) & command, sizeof (command),
  1819.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1820.     {
  1821.       fprintf (stderr, "Error :   err=%ld , [%s]\n", err, sense_errs (0, err));
  1822.     }
  1823. }
  1824.  
  1825. /*********************************************************************
  1826.  *
  1827.  *    function to seek to a cylinder
  1828.  *
  1829.  */
  1830.  
  1831. void
  1832. seek (void)
  1833.  
  1834. {
  1835.   static struct CMD_SEEK
  1836.   {
  1837.     UBYTE cmd;
  1838.     UBYTE pad_a;
  1839.     ULONG lba;
  1840.     UBYTE pad[4];
  1841.   } command =
  1842.   {
  1843.     SCSI_CMD_SKX,
  1844.     PAD,
  1845.     0,
  1846.     PAD, PAD, PAD, PAD
  1847.   };
  1848.  
  1849.   int err;
  1850.   /*
  1851.    *    load sector # (log block addr)
  1852.    */
  1853.  
  1854.   command.lba = secno;
  1855.  
  1856.   if ((err = DoScsiCmd (0, 0,
  1857.             (UBYTE *) & command, sizeof (command),
  1858.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1859.     {
  1860.       fprintf (stderr, "Error :  err = %ld , sec = %ld dec , $%lX , [%s]\n",
  1861.            err, secno, secno, sense_errs (0, err));
  1862.     }
  1863. }
  1864.  
  1865.  
  1866. /*********************************************************************
  1867.  *
  1868.  *    what CD-ROM drive?
  1869.  *
  1870.  */
  1871.  
  1872. void
  1873. finddrivebrand (void)
  1874. {
  1875.   static SCSICMD6 command =
  1876.   {
  1877.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  1878.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  1879.     PAD,            /* Page Code */
  1880.     PAD,            /* Reserved */
  1881.     0,                /* Allocation length */
  1882.     PAD                /* Control */
  1883.   };
  1884.  
  1885.   int err;
  1886.  
  1887.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  1888.  
  1889.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1890.             (UBYTE *) & command, sizeof (command),
  1891.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  1892.     {
  1893.       int rem = scsi_cmd[0].scsi_Actual;
  1894.  
  1895.       if (rem >= 8)
  1896.     {
  1897.       if (!memcmp("SONY    CD-ROM CDU-8003",
  1898.                &scsi_data[8], strlen("SONY    CD-ROM CDU-8003")))
  1899.         {
  1900.           whatdrive = APPLECD300;
  1901.         }
  1902.       else if (!memcmp("SONY    CD-ROM CDU-8002",
  1903.                 &scsi_data[8], strlen("SONY    CD-ROM CDU-8002")))
  1904.         {
  1905.           whatdrive = APPLECD150;
  1906.         }
  1907.       else if (!memcmp("TOSHIBA",
  1908.                 &scsi_data[8], strlen("TOSHIBA")))
  1909.         {
  1910.           whatdrive = TOSHIBA3401;
  1911.         }
  1912.     }
  1913.       else
  1914.     whatdrive = UNKNOWN;
  1915.     }
  1916.   else
  1917.     /* error */
  1918.     {
  1919.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  1920.     }
  1921. }
  1922.  
  1923. /*********************************************************************
  1924.  *
  1925.  *    function to set the output volume of a CD-ROM drive
  1926.  *
  1927.  *    if (vol0 = vol1 = vol2 = vol3) == -1
  1928.  *     display current volume settings, don't change anything
  1929.  *
  1930.  */
  1931.  
  1932. void
  1933. set_volume (int vol0, int vol1, int vol2, int vol3)
  1934. {
  1935.   static int err, i, j;
  1936.   static SCSICMD6 modecommand;
  1937.   static struct volmodedata
  1938.     {
  1939.       UBYTE head[4];
  1940.       UBYTE page;    /* page code 0x0E */
  1941.       UBYTE plength;    /* page length */
  1942.       UBYTE b2;        /* bit 2: Immed, bit 1: SOTC */
  1943.       UBYTE b3;        /* reserved */
  1944.       UBYTE b4;        /* reserved */
  1945.       UBYTE b5;        /* bit 7: APRVal, bit 3-0: format of LBAs / Sec. */
  1946.       UWORD bps;    /* logical blocks per second audio playback */
  1947.       UBYTE out0;    /* lower 4 bits: output port 0 channel selection */
  1948.       UBYTE vol0;    /* output port 0 volume */
  1949.       UBYTE out1;    /* lower 4 bits: output port 1 channel selection */
  1950.       UBYTE vol1;    /* output port 1 volume */
  1951.       UBYTE out2;    /* lower 4 bits: output port 2 channel selection */
  1952.       UBYTE vol2;    /* output port 2 volume */
  1953.       UBYTE out3;    /* lower 4 bits: output port 3 channel selection */
  1954.       UBYTE vol3;    /* output port 3 volume */
  1955.     } modedata;
  1956.  
  1957.   for (i = 0; i < 4; i++)
  1958.     modedata.head[i] = 0;
  1959.  
  1960.   modecommand.opcode    = SCSI_CMD_MSE;
  1961.   modecommand.b1    = 0;
  1962.   modecommand.b2    = 0x0E;
  1963.   modecommand.b3    = 0;
  1964.   modecommand.b4    = MAX_DATA_LEN;
  1965.   modecommand.control    = 0;
  1966.  
  1967.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  1968.             (UBYTE *) &modecommand, sizeof (modecommand),
  1969.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  1970.     {
  1971.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  1972.       return;
  1973.     }
  1974.  
  1975.   for (j = (scsi_data[0]+1), i = scsi_data[3] + 4; i < j; i += scsi_data[i+1] + 2)
  1976.     {
  1977.       if (vol0 == -1 && vol1 == -1 && vol2 == -1 && vol3 == -1)
  1978.     {
  1979.       if ((scsi_data[i] & 0x3f) == 0x0e)
  1980.         {
  1981.           printf ("Immed    : %s\n", (scsi_data[i+2] & 4)? "yes" : "no");
  1982.           printf ("SOTC     : %s\n", (scsi_data[i+2] & 2)? "yes" : "no");
  1983.           printf ("APRVal   : %svalid\n", (scsi_data[i+5] & 0x80)? "" : "in");
  1984.           if (scsi_data[i+5] & 0x80)
  1985.         {
  1986.           printf ("LBA Format: ");
  1987.           if ((scsi_data[i+5] & 0x0f) == 0)
  1988.             printf ("1 second\n");
  1989.           else if ((scsi_data[i+5] & 0x0f) == 8)
  1990.             printf ("1/256 second\n");
  1991.           else
  1992.             printf ("%hu (reserved)\n", scsi_data[i+5] & 0x0f);
  1993.           printf ("LBPS      : %u\n", scsi_data[i+6]<<8 + scsi_data[i+7]);
  1994.         }
  1995.         }
  1996.       if (scsi_data[i+8] & 0x0f)
  1997.         printf ("Output 0 : %hu\n", scsi_data[i+8] & 0x0f);
  1998.       else
  1999.         printf ("Output 0 : muted\n");
  2000.       printf ("Volume 0 : %hu\n", scsi_data[i+9]);
  2001.       if (scsi_data[i+10] & 0x0f)
  2002.         printf ("Output 1 : %hu\n", scsi_data[i+10] & 0x0f);
  2003.       else
  2004.         printf ("Output 1 : muted\n");
  2005.       printf ("Volume 1 : %hu\n", scsi_data[i+11]);
  2006.       if (scsi_data[i+12] & 0x0f)
  2007.         printf ("Output 2 : %hu\n", scsi_data[i+12] & 0x0f);
  2008.       else
  2009.         printf ("Output 2 : muted\n");
  2010.       printf ("Volume 2 : %hu\n", scsi_data[i+13]);
  2011.       if (scsi_data[i+14] & 0x0f)
  2012.         printf ("Output 3 : %hu\n", scsi_data[i+14] & 0x0f);
  2013.       else
  2014.         printf ("Output 3 : muted\n");
  2015.       printf ("Volume 3 : %hu\n", scsi_data[i+15]);
  2016.     }
  2017.       
  2018.       /* should be 16 bytes */
  2019.       memcpy (&modedata.page, &scsi_data[i], 16);
  2020.     }
  2021.   if (vol0 > -1 || vol1 > -1 || vol2 > -1 || vol3 > -1)
  2022.     {
  2023.       modedata.page = 0x0e;
  2024.       modedata.plength = 0x0e;
  2025.  
  2026.       if (vol0 >= 0)
  2027.     modedata.vol0 = vol0;
  2028.       if (vol1 >= 0)
  2029.     modedata.vol1 = vol1;
  2030.       if (vol2 >= 0)
  2031.     modedata.vol2 = vol2;
  2032.       if (vol3 >= 0)
  2033.     modedata.vol3 = vol3;
  2034.  
  2035.       modecommand.opcode    = SCSI_CMD_MSL;
  2036.       modecommand.b1        = 0x10;
  2037.       modecommand.b2        = 0;
  2038.       modecommand.b3        = 0;
  2039.       modecommand.b4        = sizeof (modedata);
  2040.       modecommand.control    = 0;
  2041.  
  2042.       if ((err = DoScsiCmd ((UBYTE *) &modedata, sizeof(modedata),
  2043.                 (UBYTE *) &modecommand, sizeof (modecommand),
  2044.                 (SCSIF_WRITE | SCSIF_AUTOSENSE))) != 0)
  2045.     {
  2046.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2047.       return;
  2048.     }
  2049.     }
  2050. }
  2051.  
  2052. /*********************************************************************
  2053.  *
  2054.  *    function to make an inquiry
  2055.  *
  2056.  */
  2057.  
  2058. void
  2059. inquiry (BOOLEAN parsedoutput)
  2060. {
  2061.   static SCSICMD6 command =
  2062.   {
  2063.     SCSI_CMD_INQ,        /* 0x12 INQUIRY */
  2064.     PAD,            /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
  2065.     PAD,            /* Page Code */
  2066.     PAD,            /* Reserved */
  2067.     0,                /* Allocation length */
  2068.     PAD                /* Control */
  2069.   };
  2070.   static int err;
  2071.  
  2072.   command.b4 = MAX_DATA_LEN;    /* Allocation length = max. data length */
  2073.  
  2074.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2075.             (UBYTE *) & command, sizeof (command),
  2076.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2077.     {
  2078.       int rem = scsi_cmd[0].scsi_Actual;
  2079.  
  2080.       if (parsedoutput == FALSE)
  2081.     {
  2082.       rawhexasciioutput (scsi_data, rem, 0);
  2083.     }
  2084.       else
  2085.     /* parsed output */
  2086.     {
  2087.       static IDTOSTRING devicetype[] =
  2088.       {
  2089.         0x00, "Direct-access device (e.g., magnetic disk)",
  2090.         0x01, "Sequential-access device (e.g., magnetic tape)",
  2091.         0x02, "Printer device",
  2092.         0x03, "Processor device",
  2093.         0x04, "Write-once device (e.g., some optical disks)",
  2094.         0x05, "CD-ROM device",
  2095.         0x06, "Scanner device",
  2096.         0x07, "Optical memory device (e.g., some optical disks)",
  2097.         0x08, "Medium Changer device (e.g., jukeboxes)",
  2098.         0x09, "Communications device",
  2099.         0x0A, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2100.         0x0B, "Defined by ASC IT8 (Graphic Arts Pre-Press Devices)",
  2101.         -1, "Reserved, unknown or no device type"
  2102.       };
  2103.  
  2104.       static IDTOSTRING ansiversion[] =
  2105.       {
  2106.         0x00, "The device might or might not comply to an ANSI-approved standard.",
  2107.         0x01, "The device complies to ANSI X3.131-1986 (SCSI-1).",
  2108.         0x02, "The device complies to (SCSI-2).",
  2109.         -1, "Reserved",
  2110.       };
  2111.  
  2112.       static IDTOSTRING responseformat[] =
  2113.       {
  2114.         0x00, "SCSI-1",
  2115.         0x01, "CCS",
  2116.         0x02, "SCSI-2",
  2117.         -1, "Reserved",
  2118.       };
  2119.  
  2120.       printf ("Peripherial qualifier: %ld\n", (scsi_data[0] & 0xE0) >> 5);
  2121.       printf ("Peripherial device type: $%lx, %s\n", (scsi_data[0] & 0x1F), id2string ((scsi_data[0] & 0x1F), devicetype));
  2122.  
  2123.       printf ("Removable medium: %s\n", (scsi_data[1] & 0x80) ? "yes" : "no");
  2124.       printf ("Device type modifier: %lx\n", scsi_data[1] & 0x7F);
  2125.       printf ("ISO Version: %lx\n", (scsi_data[2] & 0xC0) >> 6);
  2126.       printf ("ECMA Version: %lx\n", (scsi_data[2] & 0x38) >> 3);
  2127.  
  2128.       printf ("ANSI-Approved Version: %ld, %s\n", scsi_data[2] & 0x07, id2string ((scsi_data[2] & 0x07), ansiversion));
  2129.  
  2130.       printf ("AENC: %s\n", (scsi_data[3] & 0x80) ? "yes" : "no");
  2131.       printf ("TrmIOP: does%s support TERMINATE I/O PROCESs message\n", (scsi_data[3] & 0x40) ? "" : "n't");
  2132.  
  2133.       printf ("Response data format: $%lx, conforms to %s\n", scsi_data[3] & 0x0F, id2string ((scsi_data[3] & 0x0F), responseformat));
  2134.       printf ("Additional length: $%lx\n", scsi_data[4]);
  2135.       printf ("INQUIRY[5-6] (Reserved): $%lx, $%lx\n", scsi_data[5], scsi_data[6]);
  2136.       printf ("RelAdr: does%s support relative addressing\n", (scsi_data[7] & 0x80) ? "" : "n't");
  2137.       printf ("WBus32: does%s support 32 wide data transfers\n", (scsi_data[7] & 0x40) ? "" : "n't");
  2138.       printf ("WBus16: does%s support 16 wide data transfers\n", (scsi_data[7] & 0x20) ? "" : "n't");
  2139.       printf ("Sync: does%s support synchronous transfers\n", (scsi_data[7] & 0x10) ? "" : "n't");
  2140.       printf ("Linked: does%s support linked commands\n", (scsi_data[7] & 0x08) ? "" : "n't");
  2141.       printf ("CmdQue: does%s support tagged command queueing\n", (scsi_data[7] & 0x02) ? "" : "n't");
  2142.       printf ("SftRe: responds to RESET condition with %s RESET alternative\n", (scsi_data[7] & 0x01) ? "soft" : "hard");
  2143.       printf ("Vendor identification: %.8s\n", &scsi_data[8]);
  2144.       printf ("Product identification: %.16s\n", &scsi_data[16]);
  2145.       printf ("Product revision level: %.4s\n", &scsi_data[32]);
  2146.       printf ("Vendor specific: %.20s\n", &scsi_data[36]);
  2147.       printf ("Reserved: %.35s\n", &scsi_data[56]);
  2148.     }
  2149.     }
  2150.   else
  2151.     /* error */
  2152.     {
  2153.       fprintf (stderr, "Error : err=%ld , %s\n", err, sense_errs (0, err));
  2154.     }
  2155. }
  2156.  
  2157. /*********************************************************************
  2158.  *
  2159.  *    function to read disk capacity
  2160.  *
  2161.  */
  2162.  
  2163. void
  2164. read_capacity (BOOLEAN parsed)
  2165. {
  2166.   static struct CMD_READ_CAPACITY
  2167.   {
  2168.     UBYTE cmd;
  2169.     UBYTE pad_a;
  2170.     ULONG lba;
  2171.     UBYTE pad_b[2];
  2172.     UBYTE pmi;
  2173.     UBYTE pad_c;
  2174.   } command =
  2175.   {
  2176.     SCSI_CMD_RCP,    /* READ CAPACITY = READ CD-ROM CAPACITY */
  2177.     PAD,        /* LUN | rsrvd. | RelAddr */
  2178.     0,            /* start from sec 0 */
  2179.     PAD, PAD,
  2180.     0,            /* PMI */
  2181.     PAD
  2182.   };
  2183.  
  2184.   int err;
  2185.  
  2186.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2187.             (UBYTE *) & command, sizeof (command),
  2188.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2189.     {
  2190.       if (parsed == TRUE)
  2191.         /* output parsed data */
  2192.         {
  2193.           ULONG sec_no = *((ULONG *) & scsi_data[0]);
  2194.           ULONG sec_size = *((ULONG *) & scsi_data[4]);
  2195.  
  2196.           printf ("Max Sec = %7ld , sec size = %4ld (capacity = %7ld KB)\n",
  2197.                   sec_no, sec_size, (sec_no * sec_size) / 1024);
  2198.         }
  2199.       else
  2200.         /* output raw data */
  2201.         {
  2202.           rawhexasciioutput (scsi_data, 8, 0);
  2203.         }
  2204.     }
  2205.   else
  2206.     {
  2207.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2208.     }
  2209. }
  2210.  
  2211. /*********************************************************************
  2212.  *
  2213.  *    function to read audio CD TOC (table of contents)
  2214.  *
  2215.  */
  2216.  
  2217. void
  2218. read_toc (int toclong)
  2219. {
  2220.   static IDTOSTRING Qfield[] =
  2221.   {
  2222.     0x00, "Sub-channel Q mode information not supplied.",
  2223.     0x01, "Sub-channel Q encodes current position data.",
  2224.     0x02, "Sub-channel Q encodes media catalog number.",
  2225.     0x03, "Sub-channel Q encodes ISRC.",
  2226.     -1, "Reserved"
  2227.   };
  2228.  
  2229.   static IDTOSTRING Qfieldshort[] =
  2230.   {
  2231.     0x00, "not.suppl.",
  2232.     0x01, "cur.posdt.",
  2233.     0x02, "med.cat.#.",
  2234.     0x03, "ISRC",
  2235.     -1, "reserved"
  2236.   };
  2237.  
  2238.   static SCSICMD10 command =
  2239.   {
  2240.     SCSI_CMD_READTOC,        /* SCSI command read table of contents */
  2241.     0,
  2242.     PAD, PAD, PAD, PAD,
  2243.     0,                /* starting track */
  2244.     0x03, 0x24,            /* max. TOC data length on current CD-ROMs 804 bytes
  2245.                    or 100 TOC track descriptors */
  2246.     PAD
  2247.   };
  2248.  
  2249.   int err, tocsize;
  2250.   UBYTE *tocptr;
  2251.  
  2252.   if ((err = DoScsiCmd ((UBYTE *) toc_buf, MAX_TOC_LEN,
  2253.             (UBYTE *) & command, sizeof (command),
  2254.             (SCSIF_READ | SCSIF_AUTOSENSE))) == 0)
  2255.     {
  2256.       tocsize = (toc_buf[0] << 8) | toc_buf[1];        /* first word encodes length */
  2257.  
  2258.       if (toclong == 0)
  2259.         /* display TOC raw form */
  2260.         {
  2261.           rawhexasciioutput(toc_buf, (toc_buf[0]<<8 | toc_buf[1]), 0);
  2262.         }
  2263.       else if (toclong == 1)
  2264.     /* display TOC short form */
  2265.     {
  2266.           printf ("TOC len: %d\n", tocsize);
  2267.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2268.  
  2269.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2270.         tocsize -= 2;
  2271.  
  2272.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2273.         {
  2274.           printf ("#%3.3d: ADR:%10.10s %-15.15s Dig.copy.%5.5s. %-9.9s %cChan. %ld\n",
  2275.               tocptr[2],
  2276.               id2string (((tocptr[1] >> 4) & 0x0F), Qfieldshort),
  2277.               (tocptr[1] & 0x01) ? "pre-emphasis" : "no-pre-emphasis",
  2278.               (tocptr[1] & 0x02) ? "prmtd" : "prohb.",
  2279.               (tocptr[1] & 0x04) ? "Data tr." : "Audio tr.",
  2280.               (tocptr[1] & 0x08) ? '4' : '2',
  2281.               ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7]))
  2282.         );
  2283.         }
  2284.     }
  2285.       else if (toclong == 2)
  2286.     /* display TOC long form */
  2287.     {
  2288.           printf ("TOC len: %d\n", tocsize);
  2289.           printf ("First/last track: %d, %d\n", toc_buf[2], toc_buf[3]);
  2290.  
  2291.       if (tocsize >= 2)    /* TOC Data Length - FTN - LTN */
  2292.         tocsize -= 2;
  2293.  
  2294.       for (tocptr = &toc_buf[4]; tocptr < (&toc_buf[4] + tocsize); tocptr += 8)
  2295.         {
  2296.  
  2297.           printf ("Track number: %d\n", tocptr[2]);
  2298.  
  2299.           printf (" ADR: $%lx: %s\n", ((tocptr[1] >> 4) & 0x0F), id2string (((tocptr[1] >> 4) & 0x0F), Qfield));
  2300.  
  2301.           printf (" Audio with%s pre-emphasis.  ", (tocptr[1] & 0x01) ? "" : "out");
  2302.           printf (" Digital copy %s\n", (tocptr[1] & 0x02) ? "permitted" : "prohibited");
  2303.           printf (" %s track.  ", (tocptr[1] & 0x04) ? "Data" : "Audio");
  2304.           printf (" %s channel audio.  ", (tocptr[1] & 0x08) ? "Four" : "Two");
  2305.  
  2306.           printf (" Absolute address: %ld\n", ((tocptr[4] << 24) | (tocptr[5] << 16) | (tocptr[6] << 8) | (tocptr[7])));
  2307.         }
  2308.     }
  2309.       else
  2310.     /* toclong is neither 0,1 or 2 - this should never happen! */
  2311.     {
  2312.       fprintf (stderr, "Error : internal error in read_toc!\n");
  2313.     }
  2314.     }
  2315.   else
  2316.     {
  2317.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2318.     }
  2319. }
  2320.  
  2321. /*********************************************************************
  2322.  *
  2323.  *    function to play audio
  2324.  *
  2325.  */
  2326.  
  2327. void
  2328. play_audio (int starttrack, int startindex, int endtrack, int endindex)
  2329. {
  2330.   static SCSICMD10 command =
  2331.   {
  2332.     SCSI_CMD_PLAYAUDIOTRACKINDEX,    /* Play audio track */
  2333.     PAD,            /* LUN */
  2334.     PAD,            /* Reserved */
  2335.     PAD,            /* Reserved */
  2336.     0,                /* Starting Track */
  2337.     0,                /* Starting Index */
  2338.     PAD,            /* Reserved */
  2339.     0,                /* Ending Track */
  2340.     0,                /* Ending Index */
  2341.     PAD                /* Control */
  2342.   };
  2343.  
  2344.   int err;
  2345.  
  2346.   command.b4 = starttrack;    /* set audio track to play */
  2347.   command.b5 = startindex;
  2348.   command.b7 = endtrack;    /* ending track */
  2349.   command.b8 = endindex;
  2350.  
  2351.   finddrivebrand ();        /* figure out drivetype */
  2352.  
  2353.   if (whatdrive == APPLECD150)
  2354.     {
  2355.       command.opcode = 0xC9;    /* Apple CD-150 / Pioneer Opcode for playing audio tracks */
  2356.     }
  2357.  
  2358.   if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
  2359.             (UBYTE *) & command, sizeof (command),
  2360.             (SCSIF_READ | SCSIF_AUTOSENSE))) != 0)
  2361.     {
  2362.       fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
  2363.     }
  2364. }
  2365.  
  2366. /*********************************************************************
  2367.  *
  2368.  *    function to compare two binary strings
  2369.  *
  2370.  *    returns FALSE if different
  2371.  */
  2372.  
  2373. int
  2374. gcomp (char *p1, char *p2, int len)
  2375. {
  2376.   while (len--)
  2377.     {
  2378.       if (*p1++ != *p2++)
  2379.     return (FALSE);
  2380.     }
  2381.   return (TRUE);
  2382. }
  2383.  
  2384. /*********************************************************************
  2385.  *
  2386.  * searches DeviceList for a device name with a given string in it.
  2387.  * - if found returns with a pointer to it, else NULL
  2388.  */
  2389.  
  2390. extern struct ExecBase *SysBase;
  2391.  
  2392. UBYTE *
  2393. GetDevName (char *grep)
  2394. {
  2395.   LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
  2396.   NODE *ln;
  2397.  
  2398.   for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
  2399.     {
  2400.       UBYTE *p = ln->ln_Name;
  2401.  
  2402.       while (*p != '.')
  2403.     {
  2404.       if (strncmp (p, grep, 4) == 0)
  2405.         {
  2406.           return (ln->ln_Name);
  2407.         }
  2408.       ++p;
  2409.     }
  2410.     }
  2411.  
  2412.   return (NULL);        /* not found */
  2413. }
  2414.  
  2415. /*********************************************************************
  2416.  *
  2417.  *    Break (^C) function
  2418.  *
  2419.  */
  2420.  
  2421. int
  2422. breakcheck (void)
  2423. {
  2424.   int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
  2425.   if (zz)
  2426.     {
  2427.       fprintf (stderr, "\n***BREAK: ^C\n");
  2428.     }
  2429.   return (zz);
  2430. }
  2431.  
  2432. #ifdef __SASC
  2433. /*********************************************************************
  2434.  *
  2435.  *  tell SAS to turn of CTRL-C checking
  2436.  */
  2437. void __regargs
  2438. __chkabort (void)
  2439. {
  2440. }
  2441.  
  2442. #endif
  2443.  
  2444. /*********************************************************************
  2445.  *
  2446.  *    function to send a scsi command (uses asynchronous I/O)
  2447.  *
  2448.  */
  2449. void
  2450. SendScsiCmd (int req, UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2451. {
  2452.  
  2453.   io_ptr[req]->io_Length = sizeof (SCSICMD);
  2454.   io_ptr[req]->io_Data = (APTR) & scsi_cmd[req];
  2455.   io_ptr[req]->io_Command = HD_SCSICMD;
  2456.  
  2457.   scsi_cmd[req].scsi_Data = (APTR) data;
  2458.   scsi_cmd[req].scsi_Length = datasize;
  2459.   scsi_cmd[req].scsi_SenseActual = 0;
  2460.   scsi_cmd[req].scsi_SenseData = scsi_sense[req];
  2461.   scsi_cmd[req].scsi_SenseLength = SENSE_LEN;
  2462.   scsi_cmd[req].scsi_Command = cmd;
  2463.   scsi_cmd[req].scsi_CmdLength = cmdsize;
  2464.   scsi_cmd[req].scsi_Flags = flags;
  2465.  
  2466.   (void) SendIO ((struct IORequest *) io_ptr[req]);
  2467.  
  2468. }
  2469.  
  2470. /*********************************************************************
  2471.  *
  2472.  *    function to wait for an asynchronous scsi command
  2473.  *
  2474.  */
  2475. int
  2476. WaitScsiCmd (int req)
  2477. {
  2478.   int i;
  2479.  
  2480.   WaitIO ((struct IORequest *) io_ptr[req]);
  2481.  
  2482.   if (scsi_cmd[req].scsi_SenseActual)
  2483.     {
  2484.       fprintf (stderr, "SENSE_DATA:");
  2485.       for (i = 0; i < scsi_cmd[req].scsi_SenseActual; i++)
  2486.     {
  2487.       fprintf (stderr, " %02x", scsi_cmd[req].scsi_SenseData[i]);
  2488.     }
  2489.       fprintf (stderr, "\n");
  2490.     }
  2491.   return (io_ptr[req]->io_Error);
  2492. }
  2493.  
  2494. /*********************************************************************
  2495.  *
  2496.  *    function to use a scsi command
  2497.  *
  2498.  */
  2499. int
  2500. DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags)
  2501. {
  2502.   int i;
  2503.  
  2504.   io_ptr[0]->io_Length = sizeof (SCSICMD);
  2505.   io_ptr[0]->io_Data = (APTR) & scsi_cmd[0];
  2506.   io_ptr[0]->io_Command = HD_SCSICMD;
  2507.  
  2508.   scsi_cmd[0].scsi_Data = (APTR) data;
  2509.   scsi_cmd[0].scsi_Length = datasize;
  2510.   scsi_cmd[0].scsi_SenseActual = 0;
  2511.   scsi_cmd[0].scsi_SenseData = scsi_sense[0];
  2512.   scsi_cmd[0].scsi_SenseLength = SENSE_LEN;
  2513.   scsi_cmd[0].scsi_Command = cmd;
  2514.   scsi_cmd[0].scsi_CmdLength = cmdsize;
  2515.   scsi_cmd[0].scsi_Flags = flags;
  2516.  
  2517.   (void) DoIO ((struct IORequest *) io_ptr[0]);
  2518.  
  2519.   if (scsi_cmd[0].scsi_SenseActual)
  2520.     {
  2521.       fprintf (stderr, "SENSE_DATA:");
  2522.       for (i = 0; i < scsi_cmd[0].scsi_SenseActual; i++)
  2523.     {
  2524.       fprintf (stderr, " %02x", scsi_cmd[0].scsi_SenseData[i]);
  2525.     }
  2526.       fprintf (stderr, "\n");
  2527.     }
  2528.   return (io_ptr[0]->io_Error);
  2529. }
  2530.  
  2531. /*********************************************************************
  2532.  *
  2533.  *    function to return an error string
  2534.  *
  2535.  *
  2536.  */
  2537.  
  2538. UBYTE *
  2539. err_str (int err)
  2540. {
  2541.  
  2542.   static UBYTE *errors[] =
  2543.   {
  2544.     " cannot issue SCSI command to self ",
  2545.     " DMA error ",
  2546.     " illegal or unexpected SCSI phase ",
  2547.     " SCSI parity error ",
  2548.     " Select timed out ",
  2549.     " status and/or sense error "
  2550.   };
  2551.  
  2552.   err -= 40;
  2553.  
  2554.   if ((err < 0) || (err > 5))
  2555.     return ("Error out-of-range");
  2556.   else
  2557.     return (errors[err]);
  2558. }
  2559.  
  2560. /*********************************************************************
  2561.  *
  2562.  *    usage function
  2563.  *
  2564.  *
  2565.  */
  2566.  
  2567. void
  2568. usage (void)
  2569. {
  2570.   static char *zz[] =
  2571.   {
  2572.     "Usage: SCSIutil [-dscsi_dev] <scsi_id> <command>\n",
  2573.     " -c[r]                 : Read capacity [raw]\n",
  2574.     " -d<l|r|s> sec blks sc : Read 16 bit digital audio(start sector/# blocks)(2)\n",
  2575.     " -D<l|r> sec blks      : Read  8 bit digital audio(left or right channel)(3)\n",
  2576.     " -e <0|1>              : Change medium (0=eject, 1=load)\n",
  2577.     " -i[r]                 : Inquiry [raw]\n",
  2578.     " -h[r] blk             : Read CD-ROM data block address header\n",
  2579.     " -l <0|1>              : Allow/Prevent medium removal\n",
  2580.     " -m <0|1>              : Stop/Start motor {0=stop, 1=start}\n",
  2581.     " -o[r] contr page      : Mode sense (contr = 0-3))\n",
  2582.     " -p st si et ei        : Play audio CD track (1-99), index (1-99)\n",
  2583.     " -r[t] sec_no          : Read sectors [use trackdisk.device]\n",
  2584.     " -s sec_no             : Seek to sector (5)\n",
  2585.     " -t[r|l]               : Display TOC of an audio CD [raw|long]\n",
  2586.     " -u[r] chan fmt track  : Read CD sub-channel information [raw] (6)\n",
  2587.     " -v [vl0 vl1 vl2 vl3]  : Set output volume channels 0-3 (7)\n",
  2588. #ifdef USE8SVX
  2589.     " -8<l|r|s> sec blks   : Read digital audio -> 8SVX (left, right or stereo) (7)\n",
  2590. #endif    /* USE8SVX */
  2591.     "\n",
  2592.     "Note 1: usually scsi_id = (BOARD * 100) + (LUN * 10) + SCSI_TARGET_ID\n",
  2593.     "     2: with 's' returns LRLRLR pairs of stereo audio, 2352 bytes per block\n",
  2594.     "        sc = Apple subcode (0=2352, 1=2368, 2=2448, 3=96 byte/block)\n",
  2595.     "     3: converted to 8 bit audio (-d and -D work with Sony CDU 561 & 8003)\n",
  2596.     "     4: contr 0: current, 1: changeable, 2: default, 3: saved values\n",
  2597.     "     5: to park heads, try sec_no of -1\n",
  2598.     "     6: Q-channel = 64, fmt: 0=Sub-Q Channel data,1=current CD-ROM pos.,\n",
  2599.     "        2=Media Catalog Number (UPC/Bar Code),3=Track ISRC\n",
  2600.     "     7: use -1 to leave volume of channel as it is, without argument shows\n",
  2601.     "        current volume settings\n",
  2602. #ifdef USE8SVX
  2603.     "     8: output 8SVX IFF (in case of stereo needs to read the CD twice)\n",
  2604. #endif    /* USE8SVX */
  2605.     ""                /* TERM */
  2606.   };
  2607.  
  2608.   int j = 0;
  2609.  
  2610.   fprintf (stderr, "SCSIutil V%s [%s : %s] - written by Gary Duncan\n",
  2611.        VERSION, __DATE__, __TIME__, pname);
  2612.   fprintf (stderr, "         (gduncan@philips.oz.au) and Heiko Rath (hr@brewhr.swb.de)\n");
  2613.  
  2614.   while (*zz[j++])
  2615.     fprintf (stderr, "%s", zz[j - 1]);
  2616. }
  2617.  
  2618. /*********************************************************************
  2619.  *
  2620.  *    sense_errs function ; prints sense errors
  2621.  *
  2622.  *
  2623.  */
  2624.  
  2625. UBYTE *
  2626. sense_errs (int req, int err)
  2627. {
  2628.   typedef struct
  2629.   {
  2630.     BYTE code;
  2631.     BYTE sense;
  2632.     UBYTE *ptr;
  2633.   } S_ERRS;
  2634.  
  2635. /*
  2636.  *    only the likely, interesting ones filled in, e.g media errors
  2637.  */
  2638.   static S_ERRS x[] =
  2639.   {
  2640.     0x00, 0x00, "No error",
  2641.     0x01, 0x04, "?",
  2642.     0x02, 0x04, "?",
  2643.     0x03, 0x04, "?",
  2644.     0x04, 0x02, "?",
  2645.     0x06, 0x04, "?",
  2646.     0x09, 0x04, "?",
  2647.     0x10, 0x03, "?",
  2648.     0x10, 0x04, "?",
  2649.     0x11, 0x03, "?",
  2650.     0x12, 0x03, "?",
  2651.     0x13, 0x03, "?",
  2652.     0x14, 0x03, "?",
  2653.     0x15, 0x04, "Seek error ",
  2654.     0x17, 0x01, "?",
  2655.     0x18, 0x01, "?",
  2656.     0x19, 0x03, "?",
  2657.     0x1A, 0x05, "?",
  2658.     0x20, 0x05, "Invalid command op code",
  2659.     0x21, 0x05, "Illegal sector address",
  2660.     0x24, 0x05, "?",
  2661.     0x25, 0x05, "Invalid LUN",
  2662.     0x26, 0x05, "Invalid field in parameter list",
  2663.     0x29, 0x06, "?",
  2664.     0x2A, 0x06, "?",
  2665.     0x31, 0x03, "?",
  2666.     0x32, 0x01, "?",
  2667.     0x32, 0x03, "?",
  2668.     0x40, 0x04, "?",
  2669.     0x41, 0x04, "?",
  2670.     0x42, 0x04, "Power-on diagnostic failure",
  2671.     0x43, 0x04, "?",
  2672.     0x45, 0x04, "Select / reselect failure ",
  2673.     0x47, 0x04, "SCSI Interface Parity Error",
  2674.     0x48, 0x0B, "?",
  2675.     0x49, 0x0B, "Illegal message drive can't support",
  2676.     -1, -1, "ILLEGAL sense!!"
  2677.   };
  2678.  
  2679.   int j = 0;
  2680.   UBYTE *p;
  2681.   char sense;
  2682.   char code;
  2683.  
  2684.   /*
  2685.    *    verify that sense data looks valid
  2686.    */
  2687.   if (((scsi_cmd[req].scsi_Status & 2) == 0) ||
  2688.       (scsi_cmd[req].scsi_SenseActual < OFFS_KEY))
  2689.     {
  2690.       return ("");
  2691.     }
  2692.   sense = scsi_cmd[req].scsi_SenseData[OFFS_KEY] & 0xF;
  2693.   code = scsi_cmd[req].scsi_SenseData[OFFS_CODE];
  2694.  
  2695.   do
  2696.     {
  2697.       p = x[j].ptr;
  2698.       if ((x[j].code == code) && (x[j].sense == sense))
  2699.     break;
  2700.   } while (x[j++].code != -1);
  2701.  
  2702.   return (p);
  2703. }
  2704.  
  2705. /*********************************************************************
  2706.  *
  2707.  *    id2string function ; return pointer to string for matching id
  2708.  *
  2709.  */
  2710.  
  2711. UBYTE *
  2712. id2string (int id, IDTOSTRING * idtable)
  2713. {
  2714.   int j = 0;
  2715.   UBYTE *p;
  2716.  
  2717.   do
  2718.     {
  2719.       p = idtable[j].ptr;
  2720.       if (idtable[j].code == id)
  2721.     break;
  2722.   } while (idtable[j++].code != -1);
  2723.   return p;
  2724. }
  2725.